package com.example.security.springboot.config;

import com.example.security.springboot.service.SpringDataUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @author yingyuwei
 * @version 1.0.0
 * @description TODO
 * @createTime 2021年02月27日 15:48:00
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {

//    @Bean
//    public UserDetailsService userDetailsService() {
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        manager.createUser(User.withUsername("user").password("password").roles("USER").build());
//        manager.createUser(User.withUsername("admin").password("password").roles("USER","ADMIN").build());
//        return manager;

//        return new SpringDataUserDetailsService();
//    }

    @Bean
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }




    /**
     * https://docs.spring.io/spring-security/site/docs/5.4.5/reference/html5/#authz-arch
     * 授权过程
     * AbstractSecurityInterceptor -> AccessDecisionManager.decide()
     * 1.拦截请求，已认证用户访问受保护的web资源将被SecurityFilterChain中的 FilterSecurityInterceptor 的子
     * 类拦截。
     * 2.获取资源访问策略，FilterSecurityInterceptor会从 SecurityMetadataSource 的子类
     * DefaultFilterInvocationSecurityMetadataSource 获取要访问当前资源所需要的权限
     * Collection<ConfigAttribute> 。
     * 3.FilterSecurityInterceptor会调用 AccessDecisionManager 进行授权决策，若决策通过，则允许访问资
     * 源，否则将禁止访问
     **/
    //多个HttpSecurity
    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/api/user/**").hasAuthority("USER")
                    .antMatchers("/api/**").authenticated()
                    .anyRequest().permitAll()
                    .and()
                    .formLogin().successForwardUrl("/login‐success");
        }
    }

    @Configuration
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
//                    .csrf().disable()   //屏蔽CSRF控制，即spring security不再限制CSRF。
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()        //允许表单登录
//                    .loginPage("/login-view")   //自定义登录页面
//                    .loginProcessingUrl("/login") //自定义登录请求
                    .successForwardUrl("/login‐success");
        }
    }
}
